Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Silex - Symfony goes micro
Search
Igor Wiedler
October 21, 2011
Programming
14
11k
Silex - Symfony goes micro
Talk on the Silex microframework as given at symfonyday 2011.
Igor Wiedler
October 21, 2011
Tweet
Share
More Decks by Igor Wiedler
See All by Igor Wiedler
Redis Bedtime Stories
igorw
1
280
Wide Event Analytics (LISA19)
igorw
4
910
a day in the life of a request
igorw
0
120
production: an owner's manual
igorw
0
150
The Power of 2
igorw
0
270
LISP 1.5 Programmer's Manual: A Dramatic Reading
igorw
0
400
The Moral Character of Software
igorw
1
260
interdisciplinary computing (domcode)
igorw
0
270
miniKanren (clojure berlin)
igorw
1
280
Other Decks in Programming
See All in Programming
単体テストの始め方/作り方
toms74209200
0
430
CSC307 Lecture 17
javiergs
PRO
0
110
機械学習って何? 5分で解説頑張ってみる
kuroneko2828
0
200
赤裸々に公開。 TSKaigiのオフシーズン
takezoux2
0
130
eBPFを用いたAIネットワーク監視システム論文の実装 / eBPF Japan Meetup #4
yuukit
3
750
Javaに鉄道指向プログラミング (Railway Oriented Pro gramming) のエッセンスを取り入れる/Bringing the Essence of Railway-Oriented Programming to Java
cocet33000
2
540
Prism.parseで 300本以上あるエンドポイントに 接続できる権限の一覧表を作ってみた
hatsu38
1
110
FormFlow - Build Stunning Multistep Forms
yceruto
1
160
Cursor AI Agentと伴走する アプリケーションの高速リプレイス
daisuketakeda
1
110
エラーって何種類あるの?
kajitack
5
140
AIエージェントによるテストフレームワーク Arbigent
takahirom
0
370
人には人それぞれのサービス層がある
shimabox
3
670
Featured
See All Featured
Stop Working from a Prison Cell
hatefulcrawdad
269
20k
How to train your dragon (web standard)
notwaldorf
92
6.1k
10 Git Anti Patterns You Should be Aware of
lemiorhan
PRO
657
60k
ピンチをチャンスに:未来をつくるプロダクトロードマップ #pmconf2020
aki_iinuma
123
52k
Making the Leap to Tech Lead
cromwellryan
134
9.3k
jQuery: Nuts, Bolts and Bling
dougneiner
63
7.8k
Easily Structure & Communicate Ideas using Wireframe
afnizarnur
194
16k
"I'm Feeling Lucky" - Building Great Search Experiences for Today's Users (#IAC19)
danielanewman
228
22k
Rails Girls Zürich Keynote
gr2m
94
14k
A Modern Web Designer's Workflow
chriscoyier
693
190k
Build The Right Thing And Hit Your Dates
maggiecrowley
36
2.7k
YesSQL, Process and Tooling at Scale
rocio
172
14k
Transcript
None
• phpBB • Symfony2 • Silex igorw
None
Silex Symfony goes micro μ
Silex is not Symfony
Microframework
None
What? • Bare bones • Routes mapped to controllers •
The ‘C’ of ‘MVC’ • REST • Single file app
Why?
Sometimes a full-stack framework is too much for a simple
task.
simple
What makes silex special?
• concise • extensible • testable
• concise • extensible • testable
• concise • extensible • testable
• concise • extensible • testable
• concise • extensible • testable
Http Kernel Interface
Response handle(Request $request)
client
request client
reponse client request
clean
PSR-0
None
Silex is not Symfony
Silex is a user interface for Symfony
require_once __DIR__.'/silex.phar'; $app = new Silex\Application(); $app->get('/', function() { return
"Hello world!"; });
Phar require_once __DIR__.'/silex.phar'; $app = new Silex\Application(); $app->get('/', function() {
return "Hello world!"; });
Application require_once __DIR__.'/silex.phar'; $app = new Silex\Application(); $app->get('/', function() {
return "Hello world!"; });
require_once __DIR__.'/silex.phar'; $app = new Silex\Application(); $app->get('/', function() { return
"Hello world!"; }); Controller
$app->run();
None
<IfModule mod_rewrite.c> RewriteEngine On RewriteBase /some/path RewriteCond %{REQUEST_FILENAME} !-f RewriteCond
%{REQUEST_FILENAME} !-d RewriteRule ^(.*)$ index.php [QSA,L] </IfModule>
server { location / { if (-f $request_filename) { break;
} rewrite ^(.*) /index.php last; } location ~ index\.php$ { fastcgi_pass /var/run/php5-fpm.sock; fastcgi_index index.php; include fastcgi_params; } }
Wait a minute!
Lambdas λ
$(function () { $("a").click(function (event) { alert("Thanks for visiting!"); });
});
PHP 5.3
$f = function ($a, $b) { return $a + $b;
}; $f(1, 2);
lazy $f = function () { exit; };
nested $f = function () { return function () {
return true; }; }; $g = $f(); $value = $g();
scope $outer = 'world'; $f = function () use ($outer)
{ $inner = 'hello'; return "$inner $outer"; }; => "hello world"
scope $helloWorld = function () { $outer = 'world'; $f
= function () use ($outer) { $inner = 'hello'; return "$inner $outer"; }; return $f(); }
passing $output = function ($info) { echo $info."\n"; }; $doStuff
= function ($output) { $output('doing some magic'); doMagic(); $output('did some magic'); };
factory $userFactory = function ($name) { return new User($name); };
// ... $user = $userFactory($_POST['name']);
Usage
$app->get('/', function () { return "Hello world!"; });
Dynamic Routing
$app->get('/hello/{name}', function ($name) use ($app) { return "Hello ".$app->escape($name); });
$app->get('/hello/{name}', function ($name) use ($app) { return "Hello ".$app->escape($name); });
Controllers
assert $app->get('/blog/{id}', function ($id) { ... }) ->assert('id', '\d+');
value $app->get('/{page}', function ($page) { ... }) ->value('page', 'index');
bind $app->get('/', function () { ... }) ->bind('homepage'); $app['url_generator']->generate('homepage')
bind $app->get('/blog/{id}', function ($id) { ... }) ->bind('blog_post'); $app['url_generator'] ->generate('blog_post',
array('id' => $id))
convert $app->get('/blog/{post}', function (Post $post) { ... }) ->convert('post', function
($post) use ($app) { $id = (int) $post; return $app['posts']->find($id); });
Before & After
$app->before(function () { ... }); $app->get('/', function () { ...
}); $app->after(function () { ... });
$app->before(function (Request $request) { $loggedIn = $request ->getSession() ->get('logged_in'); if
(!$loggedIn) { return new RedirectResponse('/login'); } });
$app->after(function (Request $request, Response $response) { // tweak the Response
});
$app->after(function ( Request $request, Response $response, ) use ($app) {
$response->headers->set('x-csrf-token', $app['csrf_token']); });
REST
• get • post • put • delete • head
• options • patch
$app->get('/posts/{id}', ...); $app->post('/posts', ...); $app->put('/posts/{id}', ...); $app->delete('/post/{id}', ...);
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; $app->post('/message', function (Request $request) { mail(
'
[email protected]
', 'New message', $request->get('body') ); return new Response('Email has been sent!', 201); });
Caching
Error Handling
use Symfony\Component\HttpFoundation\Response; $app->error(function (\Exception $e, $code) { return new Response('Whoops!',
$code); });
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; throw new NotFoundHttpException("Could not find what you were
looking for.");
$app->abort(404, "Could not find the thing.");
$app['debug'] = true;
Redirecting
$app->get('/', function () use ($app) { return $app->redirect('/hello'); });
Pimple
50 NCLOC
Symfony2 DIC Pimple
Symfony2 DIC Pimple Container
Symfony2 DIC Pimple Container Builder
Symfony2 DIC Pimple Container Builder Extension
Symfony2 DIC Pimple Container Builder Extension Loader
Symfony2 DIC Pimple Container Builder Extension XML/Yaml Loader
Symfony2 DIC Pimple Container Builder Extension XML/Yaml Compiler Loader
Symfony2 DIC Pimple Container Builder Extension XML/Yaml Compiler Loader Container
Symfony2 DIC Pimple Container Builder Extension XML/Yaml Compiler Loader Container
ServiceProvider ( )
$container = new Pimple();
$app = new Silex\Application();
Parameters $app['some_parameter'] = 'value'; $app['asset.host'] = 'http://cdn.mysite.com/'; $app['database.dsn'] = 'mysql:dbname=myapp';
Services $app['some_service'] = function () { return new Service(); };
$service = $app['some_service'];
Dependencies $app['some_service'] = function ($app) { return new Service( $app['some_other_service'],
$app['some_service.config'] ); };
Shared $app['some_service'] = $app->share(function () { return new Service(); });
Protected $app['lambda_parameter'] = $app->protect( function ($a, $b) { return $a
+ $b; }); // will not execute the lambda $add = $app['lambda_parameter']; // calling it now echo $add(2, 3);
Exposed Services • debug • request • autoloader • routes
• controllers • dispatcher • resolver • kernel
Service Providers
interface ServiceProviderInterface { function register(Application $app); }
Core Service Providers • doctrine • form • http cache
• monolog • session • swiftmailer • symfony bridges • translation • twig • url generator • validator
Twig
$app->register( new Silex\ServiceProvider\TwigServiceProvider(), array( 'twig.path' => __DIR__.'/views', 'twig.class_path' => __DIR__.'/vendor/twig/lib',
) );
$app->get('/', function () use ($app) { return $app['twig']->render('hello.twig'); });
3rd Party • doctrine orm • pomm (postgres) • predis
• mongo • KyotoTycoon • memcache • rest • markdown • gravatar • buzz • config • solr • profiler • ...
Functional Testing
• src • app.php • web • index.php • tests
• bootstrap.php • YourTest.php
src/app.php require_once __DIR__.'/../vendor/silex.phar'; ... return $app;
web/index.php $app = require_once __DIR__.'/../src/app.php'; $app->run();
tests/bootstrap.php require_once __DIR__.'/../vendor/silex.phar';
use Silex\WebTestCase; class YourTest extends WebTestCase { public function createApp()
{ return require __DIR__.'/../src/app.php'; } // tests... } tests/YourTest.php
public function testAbout() { $client = $this->createClient(); $client->request('GET', '/about'); $response
= $client->getResponse(); $this->assertTrue($response->isOk()); $this->assertContains('trashbin', $response->getContent()); $this->assertContains('github', $response->getContent()); $this->assertContains('igorw', $response->getContent()); }
phpunit.xml.dist <?xml version="1.0" encoding="UTF-8"?> <phpunit backupGlobals="false" backupStaticAttributes="false" colors="true" convertErrorsToExceptions="true" convertNoticesToExceptions="true"
convertWarningsToExceptions="true" processIsolation="false" stopOnFailure="false" syntaxCheck="false" bootstrap="tests/bootstrap.php" > <testsuites> <testsuite name="YourApp Test Suite"> <directory>./tests/</directory> </testsuite> </testsuites> </phpunit>
$ phpunit
None
None
• smallish sites • well-defined scope • prototyping • restful
apis When to use
and many more...
The future
The future • Cookbooks
The future • Cookbooks • Best practices
The future • Cookbooks • Best practices • Symfony2 integration
The future • Cookbooks • Best practices • Symfony2 integration
• FOSUserBundle
The future • Cookbooks • Best practices • Symfony2 integration
• FOSUserBundle • Composer
on github fabpot/Silex fabpot/Pimple
silex.sensiolabs.org
Ω
Questions? joind.in/3699 @igorwesome speakerdeck.com /u/igorw